/*
 * This file is part of the Sx Framework Library.
 * 
 * Copyright (C) 2013 University of Colorado Denver
 * <min.choi@ucdenver.edu> <shane.transue@ucdenver.edu>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */
#ifndef SX_DISTANCES_H
#define SX_DISTANCES_H

#include <sxMath.h>

namespace Sx {
namespace Math {
namespace Distances {

/*
 * This function calculates the distance between a 3D point and a 3D line
 * segment. The line segment is defined by a pair of points that are
 * the endpoints of the segment.
 *
 *  point - The Distance between this point and the segment will be calculated.
 *  segment_p0 - The first endpoint of the segment
 *  segment_p1 - The second endpoint of the segment.
 *
 * Returns the distance between the provided point and line segment.
 */
float PointToSegmentDistance(const Eigen::Vector3f& point, const Eigen::Vector3f& segment_p0, const Eigen::Vector3f& segment_p1);

/*
 * Returns the point on the provided segment such that the dot product between
 * the provided point and the lines is 0.0 (unless the projection of the point
 * is not within the bounds of the segment, in that case it will return the
 * closest end_point).
 */
Eigen::Vector3d ClosestPointOnSegment(const Eigen::Vector3d& segment_p0, const Eigen::Vector3d& segment_p1, const Eigen::Vector3d& point);

/*
 * Returns the point on the provided segment such that the dot product between
 * the provided point and the lines is 0.0.
 */
Eigen::Vector3d ClosestPointOnLine(const Eigen::Vector3d& segment_p0, const Eigen::Vector3d& segment_p1, const Eigen::Vector3d& point);

/*
 * This function returns a normalized directional vector from the provided point
 * that is co-linear with the perpendicular line formed between the segment and
 * the point (the direction points from the point to the closest point on the
 * line formed by the segment formed by segment_p0 and segment_p1).
 *
 * If there is no perpendicular line to the segment (the point is out past the
 * one of the end points) then the function will return the direction from the
 * point to the closest end point.
 */
Eigen::Vector3f PointToSegmentPerpendicularDirection(const Eigen::Vector3f& point, const Eigen::Vector3f segment_p0, const Eigen::Vector3f segment_p1);

/*
 * Calculates the distance between two line segments. The segments are provided
 * by their sets of end points.
 *
 * Segment one is defined by:
 *  segment_1_p0 - The first endpoint of line segment 1
 *  segment_1_p1 - The second endpoint of line segment 1
 * Segment two is defined by:
 *  segment_2_p0 - The first endpoint of line segment 2
 *  segment_2_p1 - The second endpoint of line segment 2
 *
 * This function returns the closest distance between the two provided line
 * segments.
 */
double SegmentToSegmentDistance(const Eigen::Vector3d& segment_1_p0, const Eigen::Vector3d& segment_1_p1, const Eigen::Vector3d& segment_2_p0, const Eigen::Vector3d& segment_2_p1);
float SegmentToSegmentDistance(const Eigen::Vector3f& segment_1_p0, const Eigen::Vector3f& segment_1_p1, const Eigen::Vector3f& segment_2_p0, const Eigen::Vector3f& segment_2_p1);

Eigen::Vector3d closesPointOnTriangle(const Eigen::Vector3d& triangle_Point0, const Eigen::Vector3d& triangle_Point1, const Eigen::Vector3d& triangle_Point2, const Eigen::Vector3d& point);

double PointToPlaneDistance(const Eigen::Vector3d& planeNormal, const Eigen::Vector3d& planePoint, const Eigen::Vector3d& point, Eigen::Vector3d& pointOnPlane);

}

}

}

#endif
